"""
高级大语言模型管理模块

提供统一的LLM服务接口、性能监控和连接测试功能。
支持本地Ollama模型和OpenAI兼容的云端大语言模型。
"""

import time
from typing import Optional, Dict, Any, List
from dataclasses import asdict

from llama_index.core.settings import Settings
from llama_index.core.llms import LLM as BaseLLM

from ..config import config, Mode
from .providers import BaseLLMProvider, OllamaLLMProvider, CustomOpenAILLMProvider
from .stats import LLMRequestStats


class LLMManager:
    """
    高级大语言模型管理器

    职责：
    1. 管理LLM提供者的选择和切换
    2. 提供统一的文本生成接口
    3. 监控请求性能和统计信息
    4. 配置LlamaIndex全局LLM设置
    """

    def __init__(self):
        """初始化LLM管理器"""
        self._provider: Optional[BaseLLMProvider] = None
        self._stats = LLMRequestStats()

    def _get_provider(self) -> BaseLLMProvider:
        """
        获取LLM提供者

        Returns:
            BaseLLMProvider: 当前配置的LLM提供者
        """
        if self._provider is None:
            llm_config = config.get_llm_config()

            if llm_config["mode"] == "local":
                self._provider = OllamaLLMProvider(
                    model_name=llm_config["model"],
                    timeout=config.ollama_timeout
                )
            else:
                self._provider = CustomOpenAILLMProvider(
                    api_key=llm_config["api_key"],
                    base_url=llm_config["base_url"],
                    model_name=llm_config["model"],
                    timeout=60  # 云端默认超时
                )

        return self._provider

    def generate_response(self, prompt: str, **kwargs) -> str:
        """
        生成响应

        Args:
            prompt: 输入提示
            **kwargs: 额外的生成参数

        Returns:
            str: 生成的响应
        """
        if not prompt.strip():
            return ""

        start_time = time.time()
        self._stats.total_requests += 1

        try:
            model = self._get_provider().get_model()
            response = model.complete(prompt, **kwargs)

            response_time = time.time() - start_time
            response_text = str(response)

            # 更新统计信息（简化版本的token估算）
            prompt_tokens = len(prompt) // 4
            response_tokens = len(response_text) // 4
            self._stats.update_success(response_time, prompt_tokens, response_tokens)

            return response_text

        except Exception as e:
            self._stats.update_failure(str(e))
            print(f"LLM生成响应失败: {e}")
            return f"抱歉，我遇到了技术问题: {str(e)}"

    def generate_streaming_response(self, prompt: str, **kwargs):
        """
        生成流式响应

        Args:
            prompt: 输入提示
            **kwargs: 额外的生成参数

        Yields:
            str: 响应片段
        """
        if not prompt.strip():
            return

        start_time = time.time()
        self._stats.total_requests += 1

        try:
            model = self._get_provider().get_model()

            # 使用流式生成
            response_gen = model.stream_complete(prompt, **kwargs)

            response_text = ""
            for delta in response_gen:
                response_text += str(delta)
                yield delta

            response_time = time.time() - start_time

            # 更新统计信息（简化版本的token估算）
            prompt_tokens = len(prompt) // 4
            response_tokens = len(response_text) // 4
            self._stats.update_success(response_time, prompt_tokens, response_tokens)

        except Exception as e:
            self._stats.update_failure(str(e))
            print(f"LLM流式生成失败: {e}")
            yield f"抱歉，我遇到了技术问题: {str(e)}"

    def configure_llama_index(self) -> None:
        """
        配置LlamaIndex全局LLM设置

        将当前LLM提供者配置为LlamaIndex的默认LLM。
        """
        provider = self._get_provider()
        Settings.llm = provider.get_model()
        print("已配置LlamaIndex全局LLM设置")

    def test_connection(self) -> Dict[str, Any]:
        """
        测试LLM连接

        Returns:
            Dict[str, Any]: 连接测试结果，包含提供者信息和测试结果
        """
        provider_info = self._get_provider().get_info()
        test_result = self._get_provider().test_connection()

        return {
            "provider_info": provider_info,
            "test_result": test_result,
            "current_mode": config.mode.value
        }

    def benchmark_performance(
        self,
        test_prompts: List[str],
        warmup_prompts: List[str] = None
    ) -> Dict[str, Any]:
        """
        基准测试LLM性能

        Args:
            test_prompts: 测试提示列表
            warmup_prompts: 预热提示列表

        Returns:
            Dict[str, Any]: 基准测试结果
        """
        if not test_prompts:
            return {"error": "没有提供测试提示"}

        # 预热
        if warmup_prompts:
            print("正在进行LLM性能基准测试预热...")
            for prompt in warmup_prompts:
                self.generate_response(prompt)

        # 正式测试
        print(f"开始LLM性能基准测试，测试 {len(test_prompts)} 个提示...")
        start_time = time.time()

        responses = []
        response_times = []

        try:
            for prompt in test_prompts:
                prompt_start_time = time.time()
                response = self.generate_response(prompt)
                prompt_response_time = time.time() - prompt_start_time

                responses.append(response)
                response_times.append(prompt_response_time)

            total_time = time.time() - start_time

            return {
                "provider_type": self._get_provider().get_info()["provider_type"],
                "total_prompts": len(test_prompts),
                "total_time": round(total_time, 3),
                "avg_response_time": round(sum(response_times) / len(response_times), 3),
                "min_response_time": round(min(response_times), 3),
                "max_response_time": round(max(response_times), 3),
                "total_tokens": self._stats.total_tokens_used,
                "avg_tokens_per_prompt": round(self._stats.total_tokens_used / len(test_prompts), 0),
                "success_rate": round(self._stats.successful_requests / self._stats.total_requests * 100, 2),
                "success": True
            }
        except Exception as e:
            return {
                "error": str(e),
                "success": False,
                "provider_type": self._get_provider().get_info()["provider_type"]
            }

    def get_stats(self) -> LLMRequestStats:
        """
        获取请求统计信息

        Returns:
            LLMRequestStats: 当前的请求统计信息
        """
        return self._stats

    def reset_stats(self) -> None:
        """重置统计信息"""
        self._stats.reset()
        print("LLM统计信息已重置")

    def get_error_logs(self) -> List[str]:
        """
        获取错误日志

        Returns:
            List[str]: 最近的错误信息列表
        """
        return self._stats.get_recent_errors(10)

    def switch_provider(self, mode: Optional[Mode] = None) -> None:
        """
        切换LLM提供者

        Args:
            mode: 目标模式，None表示根据配置自动选择
        """
        if mode and mode != config.mode:
            raise ValueError(f"无法切换到 {mode.value} 模式，当前配置为 {config.mode.value}")

        # 强制重新初始化提供者
        self._provider = None
        print(f"LLM提供者已切换到 {config.mode.value} 模式")

    @property
    def model(self) -> BaseLLM:
        """
        获取LLM模型实例

        Returns:
            BaseLLM: 当前配置的LLM模型实例
        """
        return self._get_provider().get_model()

    @property
    def model_info(self) -> Dict[str, Any]:
        """
        获取模型信息

        Returns:
            Dict[str, Any]: 包含提供者信息和统计信息的字典
        """
        provider_info = self._get_provider().get_info()
        stats_info = asdict(self._stats)

        return {
            **provider_info,
            "request_stats": stats_info,
            "current_mode": config.mode.value
        }

    def __str__(self) -> str:
        """
        返回模型信息的字符串表示

        Returns:
            str: 格式化的模型信息字符串
        """
        provider_info = self.model_info
        stats = provider_info["request_stats"]

        return f"""
=== 高级大语言模型管理器 ===
运行模式: {provider_info['current_mode']}
提供者类型: {provider_info['provider_type']}
模型名称: {provider_info.get('model_name', 'N/A')}

{'=' * 25}
本地模式信息:
- 模型名称: {provider_info.get('model_name', 'N/A')}
- 请求超时: {provider_info.get('timeout', 'N/A')}秒
- 温度参数: {provider_info.get('temperature', 'N/A')}

云端模式信息:
- API地址: {provider_info.get('base_url', 'N/A')}
- 模型名称: {provider_info.get('model_name', 'N/A')}
- 最大重试: {provider_info.get('max_retries', 'N/A')}
- 温度参数: {provider_info.get('temperature', 'N/A')}

请求统计:
- 总请求数: {stats['total_requests']}
- 成功请求: {stats['successful_requests']}
- 失败请求: {stats['failed_requests']}
- 成功率: {round(stats['successful_requests'] / stats['total_requests'] * 100, 1) if stats['total_requests'] > 0 else 0}%
- 平均响应时间: {round(stats['average_response_time'], 3)}秒
- 总Token数: {stats['total_tokens_used']}
        """.strip()


# 全局高级LLM管理器实例
llm_manager = LLMManager()